/* eslint-disable jsx-a11y/anchor-is-valid */
/*
 * @Author: 周海 zhouhaib@yonyou.com
 * @Date: 2022-09-30 19:21:44
 * @LastEditors: Zhouhai 497675647@qq.com
 * @LastEditTime: 2024-04-28 22:05:46
 */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect, useRef, useState } from 'react';
import { getMenu, treeselect, addMenu, updateMenu, delMenu } from '@/api/system/menu';
import TreeCardLayout from '@/components/treeCardLayout';
import { useStore } from '@/store';
import { MenuDomain } from '@/type.d/system';
import { AjaxResult } from '@/type.d';
import { createIcon } from '@/utils';
import request from "@/utils/request";
import { ProFormInstance, BetaSchemaForm, ProFormColumnsType, ProCard, EditableProTable, ProColumns, ActionType } from '@ant-design/pro-components';
import { Tree, Button, message, Radio, Popconfirm, Space } from 'antd';
import { v4 as uuidv4 } from 'uuid';
import './index.less';

/**
 * 表单字段配置
 */
const formConfig: ProFormColumnsType<MenuDomain>[] = [
	{
		title: '上级菜单ID',
		key: 'parentId',
		valueType: 'treeSelect',
		dataIndex: 'string',
	},
	{
		title: '菜单名称',
		key: 'menuName',
		valueType: 'text',
	},
	{
		title: '显示排序',
		key: 'orderNum',
		valueType: 'digit',
		fieldProps: {
			precision: 0
		}
	},
	{
		title: '路由地址',
		key: 'path',
		valueType: 'text',
		tooltip: '访问的路由地址，如：`user`，如外网地址需内链访问则以`http(s)://`开头'
	},
	{
		title: '组件地址',
		key: 'component',
		valueType: 'text',
		tooltip: '前端工程page下的路径'
	},
	{
		title: '菜单类型',
		key: 'menuType',
		valueType: 'radio',
		fieldProps: {
			options: [
				{
					label: '目录',
					value: 'M',
				},
				{
					label: '菜单',
					value: 'C',
				}
			]
		}
	},
	{
		title: '是否外链',
		key: 'isFrame',
		valueType: 'radio',
		tooltip: '选择是外链则路由地址需要以`http(s)://`开头',
		fieldProps: {
			options: [
				{
					label: '是',
					value: '0',
				},
				{
					label: '否',
					value: '1',
				}
			]
		}
	},
	{
		title: '显示状态',
		key: 'visible',
		valueType: 'radio',
		request: () => {
			return request({ url: '/system/dictData/type/sys_show_hide', method: 'get' }).then(
				(res) => {
					if (res && res.data) {
						return res.data.map((item: any) => {
							return {
								label: item.dictLabel,
								value: item.dictValue
							}
						})
					}
				}
			)
		}
	},
	{
		title: '菜单状态',
		key: 'status',
		valueType: 'radio',
		tooltip: '选择是外链则路由地址需要以`http(s)://`开头',
		fieldProps: {
			options: [
				{
					label: '是',
					value: '0',
				},
				{
					label: '否',
					value: '1',
				}
			]
		}
	},
];

const Menu: React.FC = () => {
	const { layoutStore, userStore } = useStore();

	const [treeDatas, setTreeDatas] = useState<any[]>([]);//所有菜单树数据

	const [disabled, setDisabled] = useState<boolean>(true);//表单是否编辑态

	const [selectdata, setSelectdata] = useState<MenuDomain>();//选中的菜单树数据

	const [selectedTreeKeys, setSelectedTreeKeys] = useState<string[]>([]);//选中的菜单树主键

	const [oldSelectdata, setOldSelectdata] = useState<MenuDomain>();//编辑状态临时保存选中的菜单树数据

	const [tabledatas, setTabledatas] = useState<MenuDomain[]>([]);//按钮表格数据

	const [editableKeys, setEditableKeys] = useState<React.Key[] | undefined>();//按钮表格编辑的行id

	const formRef = useRef<ProFormInstance<MenuDomain>>();//表单ref

	const tableRef = useRef<ActionType>();//按钮表格ref


	/**
	 * 按钮树列配置
	 */
	const tablecolumns: ProColumns<MenuDomain>[] = [
		{
			title: '按钮名称',
			dataIndex: 'menuName',
			width: '100px'
		},
		{
			title: '权限标识',
			dataIndex: 'perms',
			width: '100px'
		},
		{
			title: '显示排序',
			dataIndex: 'orderNum',
			width: '100px'
		},
		{
			title: '操作',
			valueType: 'option',
			width: 250,
			render: (text, record, _, action) => [
				<a
					key="edit"
					hidden={!userStore.hasPerms('system:menu:edit')}
					onClick={() => {
						if (record.menuId) {
							action?.startEditable?.(record.menuId);
						}

					}}
				>
					编辑
				</a>,
				<a hidden={!userStore.hasPerms('system:menu:remove')}>
					<Popconfirm
						key="delete"
						title="确定删除该数据吗?"
						onConfirm={() => {
							if (record.menuId) {
								onTableDel(record.menuId)
							}

						}}
					>
						<a
							key="bdelete"
						>
							删除
						</a>
					</Popconfirm>
				</a>
			],
		},
	]

	/**
	 * 
	 * @param selectedKeys 菜单树选中事件
	 * @param info 
	 * @returns 
	 */
	const onSelect = (selectedKeys: (string | number)[], info: any) => {
		if (!selectedKeys || selectedKeys.length === 0) {
			return
		}
		layoutStore.OpenSpanning()
		getMenu(selectedKeys[0] as string).then((res) => {
			setSelectdata(res.data.menu)
			if (editableKeys && editableKeys.length > 0) {
				tableRef.current?.cancelEditable(editableKeys[0])
			}
			if (res.data.children) {
				setTabledatas(res.data.children.map((e: { children: any; }) => {
					delete e.children
					return e
				}))
			} else {
				setTabledatas([])
			}

		}).finally(() => {
			setSelectedTreeKeys(selectedKeys as string[])
			layoutStore.CloseSpanning()
		})

	};

	/**
	 * 根据后台返回的菜单树数据，组装成前端树组件需要的数据格式
	 * @param datas 
	 * @returns 
	 */
	const buildTreeData = (datas: []): any[] => {
		return datas.map((data: any) => {
			return {
				title: data.dictLabel,
				key: data.dictValue,
				icon: createIcon(data.icon),
				children: data.children ? buildTreeData(data.children) : [],
			};
		});
	};

	/**
	 * 页面加载完成后，调用后台查询菜单树的数据
	 */
	const getTreeDatas = () => {
		treeselect().then((res: AjaxResult) => {
			if (res.code === 200) {
				formRef.current?.resetFields(['parentId'])
				const datas: [] = res.data;
				const trees = buildTreeData(datas);
				setTreeDatas(trees);
			}
		});
	};

	/**
	 * 按钮表格新增事件
	 */
	const onTableAdd = () => {
		if (!disabled) {
			message.warning('表单编辑状态下不可新增')
			return
		}
		tableRef.current?.addEditRecord?.({
			menuId: 'ADD' + uuidv4(),//新增时创建一个虚拟id，id以ADD开头，用于保存时判断是新增还是修改
			parentId: selectdata?.menuId,
			menuName: '',
			orderNum: (tabledatas?.length ? tabledatas?.length : 0) + 1,
			perm: '',
			isFrame: '1',
			isCache: '0',
			menuType: 'F',
			visible: '0',
			status: '0',
			icon: '#',
			component: ''
		});
	}

	/**
	 * 按钮表格删除事件
	 */
	const onTableDel = async (id: React.Key | React.Key[]) => {
		if (id) {
			await delMenu(id as string).then((res) => {
				setTabledatas(tabledatas.filter((item: MenuDomain) => {
					return item.menuId !== id
				}))
				message.success('删除成功！');
			}).catch((e) => {
				console.log('删除报错了');
				throw new Error(e)
			})
		}
	}

	/**
	 * 按钮表格保存事件，在方法内部判断新增还是修改，需要注意，请求方法一定要加await，否则请求报错，不会保留当前新增的数据
	 * @param key 
	 * @param record 
	 */
	const onTableSave = async (key: React.Key | React.Key[], record: MenuDomain) => {
		if (record.menuId && typeof (record.menuId) == 'string' && record.menuId.startsWith('ADD')) {//新增
			record.menuId = undefined;
			await addMenu(record).then((res) => {
				delete res.data.children
				setTabledatas([...tabledatas, res.data])
			}).catch((e) => {
				throw new Error(e)
			})
		} else {//编辑
			await updateMenu(record).then((res) => {
				setTabledatas(tabledatas.map((item) => {
					if (item.menuId === res.data.menuId) {
						delete res.data.children
						return res.data;
					}
					return item;
				}))
				// tableRef.current?.reloadAndRest?.()
			}).catch((e) => {
				console.log('编辑报错了');
				throw new Error(e)
			})
		}
	}

	useEffect(() => {
		//初始化完成，加载左面菜单树数据
		getTreeDatas();
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	useEffect(() => {
		//选中的数据发生变化时，更新右侧form表单
		if (selectdata) {
			formRef.current?.setFieldsValue(selectdata);
		} else {
			formRef.current?.setFieldsValue({});
			formRef.current?.resetFields()
		}

	}, [selectdata]);

	const onFormAdd = () => {
		if (selectdata && selectdata.menuId && selectdata.menuType === 'M') {
			const newdata = {
				menuId: 'ADD' + uuidv4(),//新增时创建一个虚拟id，id以ADD开头，用于保存时判断是新增还是修改
				parentId: selectdata ? selectdata.menuId : '0',
				menuName: '',
				orderNum: 1,
				perm: '',
				isFrame: '1',
				isCache: '0',
				menuType: 'C',
				visible: '0',
				status: '0',
				icon: '#',
				component: ''
			}

			setOldSelectdata({ ...selectdata })//编辑时临时保存
			setSelectdata(newdata)
			setDisabled(false);
		} else {
			message.warning('请先选中一条虚菜单')
		}



	}

	const onFormSave = () => {
		const newdata = formRef.current?.getFieldFormatValueObject?.()
		layoutStore.OpenSpanning()
		const id = newdata?.menuId
		if (typeof (id) == 'string' && id.startsWith('ADD')) {
			delete newdata?.menuId
			addMenu(newdata).then((res) => {
				setSelectdata(res.data)
				setSelectedTreeKeys([res.data.menuId])
				//重新刷新左侧树的数据
				getTreeDatas();
				setDisabled(true)
				message.success('保存成功')
			}).finally(() => {
				layoutStore.CloseSpanning()
			})
		} else {
			updateMenu(newdata).then((res) => {
				setSelectdata(res.data)
				setSelectedTreeKeys([res.data.menuId])
				//重新刷新左侧树的数据
				getTreeDatas();
				setDisabled(true)
				message.success('保存成功')
			}).finally(() => {
				layoutStore.CloseSpanning()
			})
		}


	}

	const onFormEdit = () => {
		if (selectdata && selectdata.menuId) {
			setOldSelectdata({ ...selectdata })//编辑时临时保存
			setDisabled(false);
		} else {
			message.warning('请先选中一条数据')
		}

	}

	const onFormDelete = () => {
		if (selectdata && selectdata.menuId) {
			layoutStore.OpenSpanning()
			delMenu(selectdata.menuId).then((res) => {
				getTreeDatas();
				setSelectdata({})
				setSelectedTreeKeys([])
				message.success('删除成功！');
			}).catch((e) => {
				console.log('删除报错了');
				throw new Error(e)
			}).finally(() => {
				layoutStore.CloseSpanning()
			})
		} else {
			message.warning('请先选中一条数据')
		}

	}

	const onFormCancel = () => {
		if (selectdata && selectdata.menuId) {
			setSelectdata({ ...oldSelectdata })//更新回编辑时临时保存
			setOldSelectdata({})
			setDisabled(true);
		}
	}

	const rendHeadButton = (_isedit: boolean) => {
		return _isedit ?
			<Space>
				<Button
					key="save"
					type="primary"
					size='small'
					onClick={onFormSave}
				>
					保存
				</Button>
				<Button
					key="cancel"
					type="primary"
					size='small'
					onClick={onFormCancel}
				>
					取消
				</Button>
			</Space> : <Space>
				<Button
					hidden={!userStore.hasPerms('system:menu:add')}
					key="add"
					type="primary"
					size='small'
					onClick={onFormAdd}
				>
					新增
				</Button>
				<Button
					hidden={!userStore.hasPerms('system:menu:edit')}
					key="edit"
					type="primary"
					size='small'
					onClick={onFormEdit}
				>
					修改
				</Button>
				<Button
					hidden={!userStore.hasPerms('system:menu:remove')}
					key="delete"
					type="primary"
					size='small'
					onClick={onFormDelete}
				>
					删除
				</Button>
			</Space>
	}

	return (
		<TreeCardLayout
			title={'菜单'}
			titleIcon={'MenuUnfoldOutlined'}
			headButton={rendHeadButton(!disabled)}
			treeNode={
				<Tree
					showLine={true}
					showIcon={true}
					onSelect={onSelect}
					treeData={treeDatas}
					selectedKeys={selectedTreeKeys}
				/>
			}
			cardNode={
				<div className='card'>
					<div className='form'>
						<BetaSchemaForm<MenuDomain>
							labelCol={{ flex: '100px' }}
							labelAlign='left'
							labelWrap = {true}
							wrapperCol={{ flex: 1 }}
							layout={'inline'}
							grid={true}
							rowProps={{
								gutter: [16, 16],
							}}
							colProps={
								{
									sm: 12,
									lg: 8,
									xxl: 6

								}
							}
							disabled={disabled}
							formRef={formRef}
							initialValues={selectdata}
							columns={formConfig}
							submitter={{
								render: (_, dom) => <>{ }</>,
							}}
						/>
					</div>
					<div className='table'>
						<EditableProTable<MenuDomain>
							toolBarRender={() => [
								<Button key="button" size='small' type="primary" onClick={onTableAdd} hidden={selectdata ? !userStore.hasPerms('system:menu:add') : true}>
									增行
								</Button>,
							]}
							controlled
							actionRef={tableRef}
							rowKey="menuId"
							columns={tablecolumns}
							value={tabledatas}
							bordered
							size='small'
							// 关闭默认的新建按钮
							recordCreatorProps={false}
							editable={{
								type: 'multiple',
								onChange: setEditableKeys,
								editableKeys: editableKeys,
								onSave: onTableSave,
								actionRender: (row, config, defaultDom) => [defaultDom.save, defaultDom.cancel],
							}} />
					</div>


				</div>

			}
		/>
	);
};
export default Menu;
